from channels.generic.websocket import AsyncWebsocketConsumer
from device.models import Device, State
from logger.models import Logger
from user.authentication_module import TokenAuth
from channels.db import database_sync_to_async
from asgiref.sync import async_to_sync
from channels.layers import get_channel_layer
channel_layer = get_channel_layer()


async def change_device_state():
    await channel_layer.group_send(
        device_state_change_group, {"type": "deivce_change"})


def sync_change_device_state():
    async_to_sync(channel_layer.group_send)(
        device_state_change_group, {"type": "deivce_change"})


class LoggerConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        self.device = self.scope['url_route']['kwargs']['id']
        self.device_group = 'logger_%s' % self.device

        # 加入group
        await self.channel_layer.group_add(
            self.device_group,
            self.channel_name
        )

        await self.accept()

    async def disconnect(self, code):
        # 退出组
        await self.channel_layer.group_discard(
            self.device_group,
            self.channel_name
        )

    async def receive(self, text_data=None, bytes_data=None):
        await self.channel_layer.group_send(
            self.device_group,
            {
                'type': 'logger_message',
                'message': text_data
            }
        )

    # 发送消息

    async def logger_message(self, event):
        message = event['message']
        await self.send(text_data=message)


class LoggerSendConsumer(LoggerConsumer):
    @database_sync_to_async
    def get_device(self):
        return Device.objects.get(id=self.device)

    @database_sync_to_async
    def save(self, device):
        return device.save()

    @database_sync_to_async
    def save_message(self, msg):
        Logger(deviceId=self.device_data, content=msg).save()

    async def connect(self):
        self.device = self.scope['url_route']['kwargs']['id']
        self.device_group = 'logger_%s' % self.device
        try:
            self.device_data = await self.get_device()
            # 将设备状态改为在线
            self.device_data.state = State.ONLINE
            await self.save(self.device_data)
            await super().connect()
            await change_device_state()
        except Device.DoesNotExist:
            pass

    async def disconnect(self, code):
        try:
            device = await self.get_device()
            # 将设备状态改为离线
            device.state = State.OFFLINE
            await self.save(device)
            await change_device_state()
        except Device.DoesNotExist:
            pass
        await super().disconnect(code)

    async def logger_message(self, event):
        await super().logger_message(event)
        await self.save_message(event['message'])


class LoggerReceiveConsumer(LoggerConsumer):
    authentication_classes = [TokenAuth]


device_state_change_group = 'device_state_change'


class DeviceChangeConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        # 加入group
        await self.channel_layer.group_add(
            device_state_change_group,
            self.channel_name
        )
        await self.accept()

    async def disconnect(self, code):
        # 退出组
        await self.channel_layer.group_discard(
            device_state_change_group,
            self.channel_name
        )

    async def receive(self):
        await self.channel_layer.group_send(
            device_state_change_group, {'type': 'deivce_change'}
        )

    @database_sync_to_async
    def get_device(self):
        return Device.objects.all().order_by("state")

    # 发送消息

    async def deivce_change(self, event):
        await self.send('设备状态更新')


class CommandConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        self.device = self.scope['url_route']['kwargs']['id']
        self.device_group = 'command_%s' % self.device

        # 加入group
        await self.channel_layer.group_add(
            self.device_group,
            self.channel_name
        )

        await self.accept()

    async def disconnect(self, code):
        # 退出组
        await self.channel_layer.group_discard(
            self.device_group,
            self.channel_name
        )

    async def receive(self, text_data=None, bytes_data=None):
        await self.channel_layer.group_send(
            self.device_group,
            {
                'type': 'command_message',
                'message': text_data
            }
        )

    # 发送消息

    async def command_message(self, event):
        message = event['message']
        await self.send(text_data=message)


class InstallConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        self.device = self.scope['url_route']['kwargs']['id']
        self.group_name = 'install_apk_%s' % self.device

        # 加入group
        await self.channel_layer.group_add(
            self.group_name,
            self.channel_name
        )

        await self.accept()

    async def disconnect(self, code):
        # 退出组
        await self.channel_layer.group_discard(
            self.group_name,
            self.channel_name
        )

    async def receive(self):
        await self.channel_layer.group_send(
            self.group_name,
            {
                'type': 'deivce_install',
            }
        )

    # 发送消息
    async def deivce_install(self, event):
        await self.send(text_data='install')


def notify_device_install(device_id):
    group_name = "install_apk_%s" % device_id
    async_to_sync(channel_layer.group_send)(
        group_name, {"type": "deivce_install"})
